package com.lfc.myframe.utils

import android.annotation.SuppressLint
import android.content.Context
import android.content.SharedPreferences
import android.text.TextUtils
import android.util.Base64
import com.lfc.myframe.MyApp
import com.lfc.myframe.share.SP_Params
import com.lfc.myframe.share.SP_Params.PREFERENCE_NAME
import org.json.JSONArray
import org.json.JSONException
import org.json.JSONObject
import java.io.*
import java.util.*
import kotlin.reflect.KProperty

/**
 * Created by chenxz on 2018/4/21.
 * kotlin委托属性+SharedPreference实例
 */
class Preference<T>(val name: String, private val default: T) {

    companion object {
        private val file_name = PREFERENCE_NAME

        private val prefs: SharedPreferences by lazy {
            MyApp.context.getSharedPreferences(file_name, Context.MODE_PRIVATE)
        }

        /**
         * 删除全部数据
         */
        fun clearPreference() {
            prefs.edit().clear().apply()
        }

        /**
         * 根据key删除存储数据
         */
        fun clearPreference(key: String) {
            prefs.edit().remove(key).apply()
        }

        /**
         * 查询某个key是否已经存在
         *
         * @param key
         * @return
         */
        fun contains(key: String): Boolean {
            return prefs.contains(key)
        }

        /**
         * 返回所有的键值对
         *
         * @param context
         * @return
         */
        fun getAll(): Map<String, *> {
            return prefs.all
        }

        /**
         * 重置用户信息
         */
        fun resetuserinfo() {
            clearPreference(SP_Params.Token)
            clearPreference(SP_Params.UserID)
            clearPreference(SP_Params.UserPW)
            clearPreference(SP_Params.ClientNum)
            clearPreference(SP_Params.ASKSign)
            clearPreference(SP_Params.UserInfo)
        }
    }

    operator fun getValue(thisRef: Any?, property: KProperty<*>): T {
        return getSharedPreferences(name, default)
    }

    operator fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
        putSharedPreferences(name, value)
    }

    @SuppressLint("CommitPrefEdits")
    private fun putSharedPreferences(name: String, value: T) = with(prefs.edit()) {
        when (value) {
            is Long -> putLong(name, value)
            is String -> putString(name, value)
            is Int -> putInt(name, value)
            is Boolean -> putBoolean(name, value)
            is Float -> putFloat(name, value)
            is List<*> -> putString(name, SceneList2String2(value))
            is Map<*, *> -> putString(name, putHashMapData(value))
            is Any -> putString(name, putObject(value))
            else -> putString(name, serialize(value))
        }.apply()
    }

    @Suppress("UNCHECKED_CAST")
    private fun getSharedPreferences(name: String, default: T): T = with(prefs) {
        val res: Any = when (default) {
            is Long -> getLong(name, default)
            is String -> getString(name, default).toString()
            is Int -> getInt(name, default)
            is Boolean -> getBoolean(name, default)
            is Float -> getFloat(name, default)
            is List<*> -> getList2(getString(name, "").toString())!!
            is Map<*, *> ->
//                mutableMapOf<String, String>()
                getHashMapData(getString(name, "").toString())!!
            is Any ->
                if (getObject(getString(name, "")) != null)
                    getObject(getString(name, ""))!!
                else default
            else -> deSerialization(getString(name, serialize(default)).toString())
        }
        return res as T
    }

    /**
     * 序列化对象

     * @param person
     * *
     * @return
     * *
     * @throws IOException
     */
    @Throws(IOException::class)
    private fun <A> serialize(obj: A): String {
        val byteArrayOutputStream = ByteArrayOutputStream()
        val objectOutputStream = ObjectOutputStream(
            byteArrayOutputStream
        )
        objectOutputStream.writeObject(obj)
        var serStr = byteArrayOutputStream.toString("ISO-8859-1")
        serStr = java.net.URLEncoder.encode(serStr, "UTF-8")
        objectOutputStream.close()
        byteArrayOutputStream.close()
        return serStr
    }

    /**
     * 反序列化对象

     * @param str
     * *
     * @return
     * *
     * @throws IOException
     * *
     * @throws ClassNotFoundException
     */
    @Suppress("UNCHECKED_CAST")
    @Throws(IOException::class, ClassNotFoundException::class)
    private fun <A> deSerialization(str: String): A {
        val redStr = java.net.URLDecoder.decode(str, "UTF-8")
        val byteArrayInputStream = ByteArrayInputStream(
            redStr.toByteArray(charset("ISO-8859-1"))
        )
        val objectInputStream = ObjectInputStream(
            byteArrayInputStream
        )
        val obj = objectInputStream.readObject() as A
        objectInputStream.close()
        byteArrayInputStream.close()
        return obj
    }

    //<editor-fold desc="-保存对象">

    /**
     * 保存序列化对象到本地（使用时记得在bean类中实现Serializable接口）
     *
     * @param context
     * @param key
     * @param object
     */
    fun putObject(
        `object`: Any?
    ): String? {

        //先将序列化结果写到byte缓存中，其实就分配一个内存空间
        val bos = ByteArrayOutputStream()
        var os: ObjectOutputStream? = null
        try {
            os = ObjectOutputStream(bos)
            os.writeObject(`object`) //将对象序列化写入byte缓存
        } catch (e: IOException) {
            e.printStackTrace()
        }
        //将序列化的数据转为16进制保存
        return bytesToHexString(bos.toByteArray())
    }

    /**
     * desc:将数组转为16进制
     *
     * @param bArray
     * @return
     */
    fun bytesToHexString(bArray: ByteArray?): String? {
        if (bArray == null) {
            return null
        }
        if (bArray.size == 0) {
            return ""
        }
        val sb = StringBuffer(bArray.size)
        var sTemp: String
        for (i in bArray.indices) {
            sTemp = Integer.toHexString(0xFF and bArray[i].toInt())
            if (sTemp.length < 2) sb.append(0)
            sb.append(sTemp.toUpperCase())
        }
        return sb.toString()
    }

    /**
     * 从本地反序列化获取对象
     *
     * @param context
     * @param key
     * @return
     */
    fun getObject(string: String?): Any? {
        return if (TextUtils.isEmpty(string)) {
            null
        } else { //将16进制的数据转为数组，准备反序列化
            val stringToBytes = StringToBytes(string)
            val bis = ByteArrayInputStream(stringToBytes)
            var `is`: ObjectInputStream? = null
            //返回反序列化得到的对象
            var readObject: Any? = null
            try {
                `is` = ObjectInputStream(bis)
                readObject = `is`.readObject()
            } catch (e: Exception) {
                e.printStackTrace()
            }
            readObject
        }
        return null
    }

    /**
     * desc:将16进制的数据转为数组
     *
     * @param data
     * @return
     */
    fun StringToBytes(data: String?): ByteArray? {
        val hexString = data!!.toUpperCase().trim { it <= ' ' }
        if (hexString.length % 2 != 0) {
            return null
        }
        val retData = ByteArray(hexString.length / 2)
        var i = 0
        while (i < hexString.length) {
            var int_ch: Int // 两位16进制数转化后的10进制数
            val hex_char1 = hexString[i] //两位16进制数中的第一位(高位*16)
            var int_ch1: Int
            int_ch1 =
                if (hex_char1 >= '0' && hex_char1 <= '9') (hex_char1.toInt() - 48) * 16 // 0 的Ascll - 48
                else if (hex_char1 >= 'A' && hex_char1 <= 'F') (hex_char1.toInt() - 55) * 16 // A 的Ascll - 65
                else return null
            i++
            val hex_char2 = hexString[i] //两位16进制数中的第二位(低位)
            var int_ch2: Int
            int_ch2 =
                if (hex_char2 >= '0' && hex_char2 <= '9') hex_char2.toInt() - 48 // 0 的Ascll - 48
                else if (hex_char2 >= 'A' && hex_char2 <= 'F') hex_char2.toInt() - 55 // A 的Ascll - 65
                else return null
            int_ch = int_ch1 + int_ch2
            retData[i / 2] = int_ch.toByte() //将转化后的数放入Byte里
            i++
        }
        return retData
    }

    //</editor-fold>

    //<editor-fold desc="-保存集合">

    //将list集合转换成字符串
    @Throws(IOException::class)
    fun SceneList2String2(SceneList: List<*>?): String? {
// 实例化一个ByteArrayOutputStream对象，用来装载压缩后的字节文件。
        val byteArrayOutputStream = ByteArrayOutputStream()
        // 然后将得到的字符数据装载到ObjectOutputStream
        val objectOutputStream = ObjectOutputStream(
            byteArrayOutputStream
        )
        // writeObject 方法负责写入特定类的对象的状态，以便相应的 readObject 方法可以还原它
        objectOutputStream.writeObject(SceneList)
        // 最后，用Base64.encode将字节文件转换成Base64编码保存在String中
        val SceneListString = String(
            Base64.encode(
                byteArrayOutputStream.toByteArray(), Base64.DEFAULT
            )
        )
        // 关闭objectOutputStream
        objectOutputStream.close()
        return SceneListString
    }
    //将字符串转换成list集合

    //将字符串转换成list集合
    @Throws(
        StreamCorruptedException::class,
        IOException::class,
        ClassNotFoundException::class
    )
    fun String2SceneList2(SceneListString: String): List<*>? {
        val mobileBytes = Base64.decode(
            SceneListString.toByteArray(),
            Base64.DEFAULT
        )
        val byteArrayInputStream = ByteArrayInputStream(
            mobileBytes
        )
        val objectInputStream = ObjectInputStream(
            byteArrayInputStream
        )
        val SceneList = objectInputStream.readObject() as List<*>
        objectInputStream.close()
        return SceneList
    }

    fun putList2(
        key: String?,
        value: List<*>?
    ): Boolean {
        /* var str_value: String? = ""
         try {
             str_value = PreferencesUtils.SceneList2String2(value)
             PreferencesUtils.putString(context, key, str_value)
             return true
         } catch (e: java.lang.Exception) {
             e.printStackTrace()
         }*/
        return false
    }

    fun getList2(
        str_value: String?
    ): List<*>? {
        var mlist: List<*>? = ArrayList<Any?>()
        try {
            mlist = str_value?.let { String2SceneList2(it) }
            return mlist
        } catch (e: Exception) {
            e.printStackTrace()
        }
        return mlist
    }
    //</editor-fold>

    //<editor-fold desc="-保存Map">
    fun putHashMapData(datas: Map<*, *>): String {
        val mJsonArray = JSONArray()
        val iterator: Iterator<Map.Entry<*, *>> =
            datas.entries.iterator()
        val `object` = JSONObject()
        while (iterator.hasNext()) {
            val entry: Map.Entry<*, *> =
                iterator.next()
            try {
                `object`.put(entry.key.toString(), entry.value)
            } catch (e: JSONException) {
                e.printStackTrace()
            }
        }
        mJsonArray.put(`object`)
        return mJsonArray.toString()
    }

    fun getHashMapData(
        result: String?
    ): Map<*, *>? {
        val datas: MutableMap<String, String> = mutableMapOf<String, String>()
        try {
            val array = JSONArray(result)
            for (i in 0 until array.length()) {
                val itemObject = array.getJSONObject(i)
                val names = itemObject.names()
                if (names != null) {
                    for (j in 0 until names.length()) {
                        val name = names.getString(j)
                        val value = itemObject.getString(name)
                        datas[name] = value
                    }
                }
            }
        } catch (e: JSONException) {
        }
        return datas
    }

    //</editor-fold>
    /*保存map*/


}
